package studiodiva.portfolio.client.lib.view;

import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.logical.shared.AttachEvent.Handler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;

import static studiodiva.portfolio.client.lib.lang.Lang.doLater;

import studiodiva.portfolio.client.lib.lang.Base;
import studiodiva.portfolio.client.model.HasApplication;

public abstract class View<T extends IsWidget> extends Base implements IsWidget, HasApplication {

  protected static final int NORMAL_ANIMATION = 600;
  protected static final String PIXEL = "px";
  protected static final int QUICK_ANIMATION = 250;
  protected static final int SLOW_ANIMATION = 1000;

  protected static void doLaterOnAttached(Widget widget, int delay, final Runnable runnable) {
    ensureAttached(widget, new Runnable() {
      public void run() {
        doLater(1000, runnable);
      }
    });
  }

  protected static void ensureAttached(IsWidget widget, final Runnable runnable) {
    ensureAttached(widget.asWidget(), runnable);
  }

  protected static void ensureAttached(Widget widget, final Runnable runnable) {
    if (widget.isAttached())
      runnable.run();
    else widget.addAttachHandler(new Handler() {
      public void onAttachOrDetach(AttachEvent event) {
        // TODO: handler should be removed;
        if (event.isAttached()) runnable.run();
      }
    });
  }

  private T widget;

  public final <H extends EventHandler> HandlerRegistration addDomHandler(final H handler,
      DomEvent.Type<H> type) {
    return asWidget().addDomHandler(handler, type);
  }

  public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
    return addDomHandler(handler, KeyDownEvent.getType());
  }

  public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
    return addDomHandler(handler, KeyPressEvent.getType());
  }

  public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
    return addDomHandler(handler, KeyUpEvent.getType());
  }

  public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
    return addDomHandler(handler, MouseDownEvent.getType());
  }

  public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
    return addDomHandler(handler, MouseMoveEvent.getType());
  }

  public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
    return addDomHandler(handler, MouseOutEvent.getType());
  }

  public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
    return addDomHandler(handler, MouseOverEvent.getType());
  }

  public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
    return addDomHandler(handler, MouseUpEvent.getType());
  }

  public HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) {
    return addDomHandler(handler, MouseWheelEvent.getType());
  }

  public void addStyleName(String value) {
    asWidget().addStyleName(value);
  }

  public Widget asWidget() {
    return widget.asWidget();
  }

  public int getHeight() {
    return asWidget().getOffsetHeight();
  }

  public int getWidth() {
    return asWidget().getOffsetWidth();
  }

  public void setHeight(int value) {
    setHeight(value + PIXEL);
  }

  public void setHeight(String value) {
    asWidget().setHeight(value);
  }

  public void setSize(int width, int height) {
    setWidth(width);
    setHeight(height);
  }

  public void setStyleName(String value) {
    asWidget().setStyleName(value);
  }

  public void setStyleNameAdd(String value) {
    asWidget().setStyleName(value, true);
  }

  public void setVisible(boolean value) {
    asWidget().setVisible(value);
  }

  public void setWidth(int value) {
    setWidth(value + PIXEL);
  }

  public void setWidth(String value) {
    asWidget().setWidth(value);
  }

  public T widget() {
    return widget;
  }

  protected void initWidget(T widget) {
    this.widget = widget;
  }

  protected void removeStyleName(String style) {
    asWidget().removeStyleName(style);
  }

  protected void setStyleName(String style, boolean add) {
    asWidget().setStyleName(style, add);
  }
}
